package com.kingyun.gpsinspection.purificationservice.services.tdm.innerservice.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cqhilink.api.common.utils.UniqueUtil;
import com.kingyun.gpsinspection.purificationservice.common.activiti.ActivitiConstants;
import com.kingyun.gpsinspection.purificationservice.common.utils.FileTypeUtil;
import com.kingyun.gpsinspection.purificationservice.dao.mapper.iam.accessory.OrganizationMapper;
import com.kingyun.gpsinspection.purificationservice.dao.mapper.tdm.*;
import com.kingyun.gpsinspection.purificationservice.facade.model.File;
import com.kingyun.gpsinspection.purificationservice.facade.model.jsm.Employee;
import com.kingyun.gpsinspection.purificationservice.facade.model.jsm.EmployeeVo;
import com.kingyun.gpsinspection.purificationservice.facade.model.jsm.RedisValue;
import com.kingyun.gpsinspection.purificationservice.facade.model.som.User;
import com.kingyun.gpsinspection.purificationservice.facade.model.tdm.*;
import com.kingyun.gpsinspection.purificationservice.facade.service.activiti.base.WorkFlowService;
import com.kingyun.gpsinspection.purificationservice.facade.service.jsm.employee.JsmEmployeeService;
import com.kingyun.gpsinspection.purificationservice.facade.service.tdm.IBMBPMService;
import com.kingyun.gpsinspection.purificationservice.facade.service.tdm.PatrolInspectionService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 巡回检查业务层
 * Created by sugongche on 2017/1/4.
 */
public class PatrolInspectionServiceImpl implements PatrolInspectionService {
    public Logger logger = LoggerFactory.getLogger(this.getClass());
    public static final String NORMAL_FLOW_KEY = "tour";
    public static final String CYCLE_FLOW_KEY = "timer";
    // BPM
    @Autowired
    public IBMBPMService ibmbpmService;
    @Autowired
    private PatrolInspectionMapper patrolInspectionMapper;
    @Autowired
    public TaskLinkMapper taskLinkMapper;
    @Autowired
    private TdmFileMapper tdmFileMapper;
    @Autowired
    private TdmTaskRelationMapper tdmTaskRelationMapper;
    @Autowired
    public TdmWorkOrderMapper tdmWorkOrderMapper;
    @Autowired
    public WorkOrderEmployeeMapper workOrderEmployeeMapper;
    @Autowired
    private WorkFlowService workFlowService;
    @Autowired
    private OrganizationMapper organizationMapper;
    @Autowired
    private JsmEmployeeService jsmEmployeeService;
    @Autowired
    private CustomWorkCriteriaMapper customWorkCriteriaMapper;

    /**
     * 保存
     * 注意：解开启事务，不能抛异常
     *
     * @param employeeVo
     * @param patrolInspection
     * @param uploadFiles
     * @param deletedFiles
     * @param workOrderList
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int save(EmployeeVo employeeVo, PatrolInspection patrolInspection, String uploadFiles, String deletedFiles, List<WorkOrderVo> workOrderList) {
        if (patrolInspection == null) {
            return 0;
        }
        //set任务id
        patrolInspection.setPatrolInspectionId(UniqueUtil.uuid());
        int a = 0;
        //区分周期任务和非周期任务：是否周期任务是必填项
        if (patrolInspection.getIsPeriodicTask() != null) {
            if (patrolInspection.getIsPeriodicTask() == 1) {
                /**周期任务*/
                //保存发起任务信息：没有设置流程ID
                saveBean(employeeVo, patrolInspection);
                //根据任务信息保存附件
                saveAttach(patrolInspection, uploadFiles, deletedFiles);
                //并保存工单
                saveWorkOrderList(employeeVo, patrolInspection, workOrderList);
                //修改定时任务状态为已完成
                patrolInspectionMapper.updateFinishById(patrolInspection);
                //开启流程
                try {
                    workFlowService.startProcessInstanceByKey(CYCLE_FLOW_KEY, patrolInspection.getPatrolInspectionId(), null, employeeVo.getEmployeeId());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if (patrolInspection.getIsPeriodicTask() == 0) {
                /**非周期任务*/
                //注意对象做方法参数传的是引用：此方法中设置的值，在此方法结束后，相应对象的值也改变
                a += saveBean(employeeVo, patrolInspection);
                //第二步：保存附件；根据任务信息
                a += saveAttach(patrolInspection, uploadFiles, deletedFiles);
                //保存任务相关信息：先保存任务环节，再保存工单
                a += saveTaskLinkWorkOrder(employeeVo, patrolInspection, workOrderList);
                //开启流程
                Map map = achievePersons(workOrderList);
                try {
                    workFlowService.startProcessInstanceByKey(NORMAL_FLOW_KEY, patrolInspection.getPatrolInspectionId(), map, employeeVo.getEmployeeId());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return a;
    }

    /**
     * 根据工单来获取审批人员信息
     */
    private Map achievePersons(List<WorkOrderVo> workOrderList) {
        Map map = new HashMap<>();
        List<String> names = new ArrayList<>();
        for (WorkOrderVo workOrderVo : workOrderList) {
            if (null != workOrderVo.getOrgId() && workOrderVo.getOrgId() != "") {
                List<User> list = organizationMapper.queryUsersByOrgId(workOrderVo.getOrgId());
                for (User user : list) {
                    names.add(user.getUserId());
                }
            } else if (null != workOrderVo.getUserId() && workOrderVo.getUserId() != "") {
                Employee employee = jsmEmployeeService.queryByKeyId(workOrderVo.getUserId());
                names.add(employee.getEmployeeId());
            }
        }
        map.put(ActivitiConstants.MANUAL_PERSON, names);
        return map;
    }

    /**
     * 插入关联关系
     *
     * @param patrolInspection
     * @param taskRelation
     */
    private void insertTaskRelation(TaskRelation taskRelation, PatrolInspection patrolInspection) {
        // 关系表主键
        taskRelation.setTaskRelationId(UniqueUtil.uuid());
        // 主任务ID和主任务类型已经包含在relation对象中
        taskRelation.setRelatedTaskId(patrolInspection.getPatrolInspectionId());
        taskRelation.setRelatedTaskType(patrolInspection.getTaskType());
        // 保存关联任务信息
        tdmTaskRelationMapper.insert(taskRelation);
    }

    /**
     * 保存巡回检查任务对象
     *
     * @param employeeVo
     * @param patrolInspection
     * @return
     */
    public int saveBean(EmployeeVo employeeVo, PatrolInspection patrolInspection) {
        int a;
        //新增发起任务信息
        patrolInspection.setCreateUserId(employeeVo.getEmployeeId());
        patrolInspection.setModifyUserId(employeeVo.getEmployeeId());
        //-1 正在审核；1 审核通过；0审核不通过
        patrolInspection.setAuditStatus((short) -1);
        //状态0正常；1是删除
        patrolInspection.setIsDelete((short) 0);
        //状态1是启用；0是关闭
        patrolInspection.setIsEnable(patrolInspection.getIsEnable() == null ? (short) 1 : patrolInspection.getIsEnable());
        //1 审核处理中；2 执行中；3 已完成
        patrolInspection.setTaskStatus((short) 1);
        //是否使用（定时任务分解任务时使用）0未使用，1已使用
        patrolInspection.setIsUsed((short) 0);
        //创建时间
        patrolInspection.setCreateTime(new Date());
        //修改时间
        patrolInspection.setModifyTime(new Date());
        a = patrolInspectionMapper.insert(patrolInspection);
        return a;
    }


    /**
     * 根据Bean的信息保存附件（新增和删除）
     *
     * @param patrolInspection
     * @param uploadFiles
     * @return
     */
    public int saveAttach(PatrolInspection patrolInspection, String uploadFiles, String deletedFiles) {
        int a = 0;

        //保存附件
        if (StringUtils.isNotBlank(uploadFiles)) {
            //强制转换成集合
            List<File> listFiles = JSON.parseArray(uploadFiles, File.class);
            //重新设置附件属性
            for (int i = 0; i < listFiles.size(); i++) {
                File _file = listFiles.get(i);
                //设置主键
                _file.setFileId(UniqueUtil.uuid());
                //设置业务数据id
                _file.setBusinessId(patrolInspection.getPatrolInspectionId());
                _file.setFileType((short) FileTypeUtil.getFileTypeByFileName(_file.getFileName()));
            }
            //必须判断非空
            if (listFiles != null && listFiles.size() > 0) {
                a = tdmFileMapper.insertByList(listFiles);
            }
        }

        //需要删除的附件信息
        if (StringUtils.isNotBlank(deletedFiles)) {
            //强制转换成集合
            List<File> listFiles = JSON.parseArray(deletedFiles, File.class);
            if (listFiles != null && listFiles.size() > 0) {
                int len = listFiles.size();
                for (int i = 0; i < len; i++) {
                    File _file = listFiles.get(i);
                    a += tdmFileMapper.deleteByPrimaryKey(_file.getFileId());
                }
            }
        }

        return a;
    }

    /**
     * 更新
     *
     * @param patrolInspection
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int update(PatrolInspection patrolInspection) {
        if (patrolInspection == null) {
            return 0;
        }

        int a = patrolInspectionMapper.updateByPrimaryKeyNew(patrolInspection);

        return a;
    }

    /**
     * 根据主键查询bean
     *
     * @param patrolInspectionId
     * @return
     */
    @Override
    public PatrolInspection queryBeanById(String patrolInspectionId) throws Exception {
        if (StringUtils.isBlank(patrolInspectionId)) {
            return null;
        }

        PatrolInspection patrolInspection = patrolInspectionMapper.selectByPrimaryKey(patrolInspectionId);

        return patrolInspection;
    }

    /**
     * 根据主键查询包装类
     *
     * @param patrolInspectionId
     * @return
     */
    @Override
    public PatrolInspectionVo queryVoById(String patrolInspectionId) {
        if (StringUtils.isBlank(patrolInspectionId)) {
            return null;
        }

        PatrolInspectionVo patrolInspectionVo = patrolInspectionMapper.selectByPrimaryKeyNew(patrolInspectionId);

        return patrolInspectionVo;
    }

    /**
     * 根据任务实例ID查询任务表和任务环节表
     *
     * @param piPiid
     * @return
     */
    @Override
    public PatrolInspectionVo findVoByPiPiid(String piPiid) {
        if (StringUtils.isBlank(piPiid)) {
            return null;
        }

        PatrolInspectionVo patrolInspectionVo = patrolInspectionMapper.findVoByPiPiid(piPiid);

        return patrolInspectionVo;
    }

    /**
     * 现场操作
     *
     * @param redisValue
     * @param employeeVo
     * @param patrolInspection
     * @param taskLink
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int saveBySpotOperation(RedisValue redisValue, EmployeeVo employeeVo, PatrolInspection patrolInspection, TaskLink taskLink) {
        if (taskLink == null) {
            return 0;
        }

        //用户信息
        //String username = "deadmin";
        //String password = "deadmin";
        String username = redisValue.getLoginName();
        String password = redisValue.getPassWord();
        String result = ibmbpmService.completeTask(username, password, taskLink.getTkiid(), null);

        //标志变量
        int a = 0;
        //处理返回值为空串：执行了但是没有返回值
        if ("".equals(result)) {
            logger.info("完成“" + taskLink.getTaskLinkName() + "”返回值为空串！");
        } else {
            //获得返回值
            JSONObject resultObj = JSONObject.parseObject(result);
            if (resultObj != null) {
                String status = (String) resultObj.get("status");
                //开始流程成功
                if (status != null && status.equals("200")) {
                    a = saveTaskLinkWorkOrder(employeeVo, patrolInspection, null);
                } else {
                    logger.error("完成“" + taskLink.getTaskLinkName() + "”返回状态非200！");
                }
            } else {
                logger.error("完成“" + taskLink.getTaskLinkName() + "”返回值非json字符串！");
            }
        }

        return a;
    }

    /**
     * 保存任务相关信息：先保存任务环节，再保存工单
     *
     * @param employeeVo
     * @param patrolInspection
     * @param wrokOrderList
     * @return
     */
    public int saveTaskLinkWorkOrder(EmployeeVo employeeVo, PatrolInspection patrolInspection, List<WorkOrderVo> wrokOrderList) {
        //标志变量
        int a = 0;

        //保存工单：后
        saveWorkOrderList(employeeVo, patrolInspection, wrokOrderList);

        patrolInspection.setAuditStatus((short) 1);
        a += patrolInspectionMapper.updateAuditStatusById(patrolInspection);

        //进入现场操作：更新任务状态为执行中
        a += patrolInspectionMapper.updateTaskStatusExecutedById(patrolInspection);
        //进入现场操作：所有工单状态改为可用
        a += tdmWorkOrderMapper.updateStatusEnableByTaskId(patrolInspection.getPatrolInspectionId());

        return a;
    }

    /**
     * 保存分析处理的关联的维护保养任务
     *
     * @param employeeVo
     * @param patrolInspection
     * @param uploadFiles
     * @param deletedFiles
     * @param workOrderList
     * @param analysisProcessId
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int saveRelation(EmployeeVo employeeVo, PatrolInspection patrolInspection, String uploadFiles, String deletedFiles, List<WorkOrderVo> workOrderList, String analysisProcessId) {
        if (patrolInspection == null) {
            return 0;
        }

        int a = 0;

        patrolInspection.setNode((short) -1);
        //区分周期任务和非周期任务：是否周期任务是必填项
        if (patrolInspection.getIsPeriodicTask() != null) {
            //周期任务：不走定时任务
            if (patrolInspection.getIsPeriodicTask() == 1) {
                patrolInspection.setIsUsed((short) -1);
            }
        }
        //注意对象做方法参数传的是引用：此方法中设置的值，在此方法结束后，相应对象的值也改变
        a += saveBean(employeeVo, patrolInspection);

        TaskRelation taskRelation = new TaskRelation();
        taskRelation.setTaskRelationId(UniqueUtil.uuid());
        taskRelation.setMasterTaskId(analysisProcessId);
        taskRelation.setMasterTaskType((short) 5);
        taskRelation.setRelatedTaskId(patrolInspection.getPatrolInspectionId());
        taskRelation.setRelatedTaskType(patrolInspection.getTaskType());
        a += tdmTaskRelationMapper.insert(taskRelation);

        //根据任务信息保存工单
        a += saveWorkOrderList(employeeVo, patrolInspection, workOrderList);

        //根据任务信息保存附件
        a += saveAttach(patrolInspection, uploadFiles, deletedFiles);

        return a;
    }

    /**
     * 根据任务信息保存工单
     *
     * @param employeeVo
     * @param patrolInspection
     * @param workOrderList
     * @return
     */
    public int saveWorkOrderList(EmployeeVo employeeVo, PatrolInspection patrolInspection, List<WorkOrderVo> workOrderList) {
        int a = 0;

        if (workOrderList != null && workOrderList.size() > 0) {
            //注意思路：先删除后新增
            List<WorkOrder> oldWorkOrderList = tdmWorkOrderMapper.findListByTaskId(patrolInspection.getPatrolInspectionId());

            //先根据工单Id删除工单和人员的关系表
            if (oldWorkOrderList != null && oldWorkOrderList.size() > 0) {
                for (WorkOrder oldWorkOrder : oldWorkOrderList) {
                    if (oldWorkOrder != null && oldWorkOrder.getWorkOrderId() != null) {
                        a += workOrderEmployeeMapper.deleteByWorkOrderId(oldWorkOrder.getWorkOrderId());
                    }
                }
            }

            //再根据任务Id删除该任务对应的工单：
            a += tdmWorkOrderMapper.deleteByTaskId(patrolInspection.getPatrolInspectionId());

            //重要方法：给List中的元素回设置
            for (WorkOrderVo workOrder : workOrderList) {
                //重新设置主键ID
                workOrder.setWorkOrderId(UniqueUtil.uuid());
                //关键：必须拿到任务ID
                workOrder.setTaskId(patrolInspection.getPatrolInspectionId());
                //关键：必须拿到任务类型
                workOrder.setTaskType(patrolInspection.getTaskType());
                workOrder.setCreateUserId(employeeVo.getEmployeeId());
                workOrder.setModifyUserId(employeeVo.getEmployeeId());
                //工单状态：-1预处理，0创建，1作业条件检查，2作业前准备，3操作申请（关键操作--才会申请），4审核通过，5审核不通过，6已经完成，7已关闭
                workOrder.setStatus((short) -1);
                //1是删除；0是正常
                workOrder.setIsDelete((short) 0);
                //0未下载；已经下载
                workOrder.setIsDownload((short) 0);
                //0无法完成；1可以完成
                workOrder.setCanFinish((short) 1);
                //0未确认；1已经确认
                workOrder.setConfirmStatus((short) 0);

                //先保存工单
                a += tdmWorkOrderMapper.insertNew(workOrder);

                //保存工单和人员的关系表：
                if (workOrder.getUserId() != null) {
                    String[] array = workOrder.getUserId().split(",");
                    if (array != null && array.length > 0) {
                        for (int i = 0; i < array.length; i++) {
                            if (StringUtils.isNotBlank(array[i])) {
                                WorkOrderEmployee workOrderEmployee = new WorkOrderEmployee();
                                workOrderEmployee.setWorkOrderEmployeeId(UniqueUtil.uuid());
                                workOrderEmployee.setWorkOrderId(workOrder.getWorkOrderId());
                                workOrderEmployee.setEmployeeId(array[i]);
                                a += workOrderEmployeeMapper.insert(workOrderEmployee);
                            }
                        }
                    }
                }
                //保存自定义巡检
                if (null != workOrder.getRemark() && workOrder.getRemark() != "") {
                    JSONArray jsonArray = JSON.parseArray(workOrder.getRemark());
                    List<CustomWorkCriteria> list = new ArrayList<>();
                    for (Object o : jsonArray) {
                        JSONObject jsonObject = JSON.parseObject(o.toString());
                        CustomWorkCriteria customWorkCriteria = new CustomWorkCriteria();
                        customWorkCriteria.setId(UniqueUtil.uuid());
                        customWorkCriteria.setWorkOrderId(workOrder.getWorkOrderId());
                        customWorkCriteria.setWorkInstanceId(jsonObject.get("workInstanceId").toString());
                        customWorkCriteria.setRankId(Integer.parseInt(jsonObject.get("categoryIndex").toString()));
                        customWorkCriteria.setCategory(jsonObject.get("category").toString());
                        list.add(customWorkCriteria);
                    }
                    if (list != null && list.size() > 0) {
                        customWorkCriteriaMapper.insertByList(list);
                    }
                }
            }
        }
        return a;
    }

    /**
     * 修改分析处理关联的维护保养任务页面：不走BPM
     *
     * @param employeeVo
     * @param patrolInspection
     * @param uploadFiles
     * @param deletedFiles
     * @param workOrderVoList
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int updateRelation(EmployeeVo employeeVo, PatrolInspection patrolInspection, String uploadFiles, String deletedFiles, List<WorkOrderVo> workOrderVoList) {
        if (patrolInspection == null) {
            return 0;
        }

        //标志变量
        int a = 0;

        //第一步：更新任务信息；修改人必填
        patrolInspection.setModifyUserId(employeeVo.getEmployeeId());
        a += patrolInspectionMapper.updateByPrimaryKeyNew(patrolInspection);

        //第二步：更新附件信息：新增+删除
        a += saveAttach(patrolInspection, uploadFiles, deletedFiles);

        //第三步：更新工单信息：先删除，后新增
        a += saveWorkOrderList(employeeVo, patrolInspection, workOrderVoList);

        return a;
    }


    /**
     * 发起BPM流程：和save方法相似
     *
     * @param redisValue
     * @param employeeVo
     * @param patrolInspection
     * @param workOrderVoList
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int launchBPM(RedisValue redisValue, EmployeeVo employeeVo, PatrolInspection patrolInspection, List<WorkOrderVo> workOrderVoList) {
        int a = 0;

        //String username = "deadmin";
        //String password = "deadmin";

        String username = redisValue.getLoginName();//用户名
        String password = redisValue.getPassWord();//密码
        //开始流程：需要任务类型
        String result = ibmbpmService.openBPM(employeeVo, patrolInspection.getTaskType(), username, password, null);
        //如果没有权限直接返回99
        if (result.equals("WorkSpaceError")) {
            return 99;
        }
        //如果没有权限直接返回99
        if (result.equals("WorkSpaceError")) {
            return 99;
        }
        String piid = "";//流程实例ID
        String tkiid = "";//任务节点ID
        String name = ""; //第一个任务实例节点的名称

        //获得返回值
        JSONObject resultObj = JSONObject.parseObject(result);
        if (resultObj != null) {
            String status = (String) resultObj.get("status");
            //开始流程成功
            if (status != null && status.equals("200")) {
                //获取data属性的值
                JSONObject dataObj = (JSONObject) resultObj.get("data");
                //获取tasks属性的值：只有一个元素的数组，元素包含流程实例id和第一个节点的任务id
                JSONArray itemsArray = (JSONArray) dataObj.get("tasks");
                for (int i = 0; i < itemsArray.size(); i++) {//循环json数组
                    JSONObject ob = (JSONObject) itemsArray.get(i);//得到json对象
                    piid = ob.getString("piid");//piid这里是列名称，获取json对象中列名为piid的值
                    tkiid = ob.getString("tkiid");//tkiid这里是列名称，获取json对象中列名为tkiid的值
                    name = ob.getString("name");//name是列名称，获取json对象中列名为name的值
                }

                //执行第一个任务节点
                result = ibmbpmService.completeTask(username, password, tkiid, null);
                //获得返回值
                resultObj = JSONObject.parseObject(result);
                if (resultObj != null && !"".equals(resultObj)) {
                    status = (String) resultObj.get("status");
                    //完成任务成功
                    if (status != null && status.equals("200")) {
                        //第一步：更新流程实例ID和当前节点
                        patrolInspection.setFlowId(piid);
                        patrolInspection.setNode((short) 0);
                        patrolInspection.setIsUsed((short) 0);
                        //CREATE_TIME重新赋值：代表任务发起时间，而不是任务新建时间
                        patrolInspection.setCreateTime(new Date());
                        a += patrolInspectionMapper.updateByPrimaryKeySelective(patrolInspection);

                        //第二步：保存任务环节；修改工单需要保存；
                        TaskLink taskLink = new TaskLink();
                        taskLink.setPiPiid(piid);//流程实例ID
                        taskLink.setTkiid(tkiid);//任务节点ID
                        taskLink.setTaskLinkName(name); //任务节点名称
                        //第一个节点默认通过
                        taskLink.setAuditStatus((short) 1);
                        //任务指派人可以修改工单，但不能修改任务基础信息
                        a += saveTaskLinkWorkOrder(employeeVo, patrolInspection, workOrderVoList);
                    } else {
                        logger.error("完成维护保养流程第一个任务节点失败！");
                    }
                } else {
                    logger.error("完成维护保养流程第一个任务节点无返回值！");
                }

            } else {
                logger.error("发起维护保养流程失败！");
            }
        } else {
            logger.error("发起维护保养流程无返回值！");
        }

        return a;
    }
}
